package com.greensam.pixelengine.manager.auth;

import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.json.JSONUtil;
import com.greensam.pixelengine.constant.UserConstant;
import com.greensam.pixelengine.exception.BusinessException;
import com.greensam.pixelengine.exception.ResultCode;
import com.greensam.pixelengine.exception.ThrowUtils;
import com.greensam.pixelengine.manager.auth.model.SpaceUserPermission;
import com.greensam.pixelengine.pojo.emuns.ErrorCodeEnum;
import com.greensam.pixelengine.pojo.emuns.TeamSpaceRoleEnum;
import com.greensam.pixelengine.pojo.entity.PicturePo;
import com.greensam.pixelengine.pojo.entity.SpacePo;
import com.greensam.pixelengine.pojo.entity.SpaceUserPo;
import com.greensam.pixelengine.pojo.entity.UserPo;
import com.greensam.pixelengine.service.PictureDataService;
import com.greensam.pixelengine.service.RoleDataService;
import com.greensam.pixelengine.service.SpaceDataService;
import com.greensam.pixelengine.service.SpaceUserDataService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.*;


/**
 * 自定义权限加载接口实现类
 *
 * @author Ma Chengrui
 * @since 2025/9/28 15:11
 */
@Component
@RequiredArgsConstructor
public class StpInterfaceImpl implements StpInterface {

    private final RoleDataService roleDataService;
    private final SpaceDataService spaceDataService;
    private final PictureDataService pictureDataService;
    private final SpaceUserDataService spaceUserDataService;
    private final SpaceUserAuthManager spaceUserAuthManager;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    /**
     * 返回一个账号所拥有的权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 判断 loginType，仅对登录类型为 "space" 的请求进行权限验证
        if (!StpKit.SPACE_TYPE.equals(loginType)) {
            return Collections.emptyList();
        }
        // 获取所有权限
        List<String> ALL_PERMISSIONS = spaceUserAuthManager.listAllPermissions().stream()
                .map(SpaceUserPermission::getKey)
                .toList();

        // 获取上下文对象
        SpaceUserAuthContext context = getAuthContextByRequest();
        // 获取 userId
        UserPo loginUser = (UserPo) StpKit.SPACE.getSessionByLoginId(loginId).get(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(Objects.isNull(loginUser), ResultCode.NOT_LOGIN_ERROR);
        Long userId = loginUser.getId();

        // 如果所有字段都为空，表示查询公共图库，管理员有所有权限，其他人仅查看权限
        if (isAllFieldsNullByReflect(context)) {
            return getPublicSpacePermissions(userId, ALL_PERMISSIONS);
        }

        // 优先从上下文中获取 SpaceUser 对象
        SpaceUserPo spaceUser = context.getSpaceUser();
        // 如果上下文携带 SpaceUser 对象，则直接返回对应的权限
        if (Objects.nonNull(spaceUser)) {
            return spaceUserAuthManager.listPermissionsByRole(spaceUser.getRoleCode());
        }

        // 如果有 spaceUserId，必然是团队空间，根据 SpaceUser 对象返回权限
        Long spaceUserId = context.getSpaceUserId();
        if (Objects.nonNull(spaceUserId)) {
            spaceUser = spaceUserDataService.getSpaceUserById(spaceUserId)
                    .orElseThrow(() -> new BusinessException(ErrorCodeEnum.DataNotExist, "未找到空间用户信息"));
            // 拿到该团队空间id
            Long spaceId = spaceUser.getSpaceId();
            // 查找该团队空间该用户，如果找到直接使用空间角色的权限，如果找不到则表示该用户不属于该空间无权限
            SpaceUserPo spaceUserPo = spaceUserDataService.getSpaceUserByUserIdAndSpaceId(userId, spaceId)
                    .orElse(null);
            if (Objects.nonNull(spaceUserPo)) {
                return spaceUserAuthManager.listPermissionsByRole(spaceUserPo.getRoleCode());
            } else {
                return Collections.emptyList();
            }
        }

        // 如果没有 spaceUserId，尝试通过 spaceId 获取 Space 对象，再用过空间类型分配权限
        Long spaceId = context.getSpaceId();
        if (Objects.nonNull(spaceId)) {
            SpacePo spacePo = spaceDataService.getSpaceById(spaceId)
                    .orElseThrow(() -> new BusinessException(ErrorCodeEnum.SpaceNotExist, "未找到空间信息"));
            return getPermissionsBySpaceType(ALL_PERMISSIONS, userId, spaceId, spacePo);
        }

        // 如果没有 spaceId，通过 pictureId 获取 Picture 对象和 Space 对象，再用过空间类型分配权限
        Long pictureId = context.getPictureId();
        if (Objects.nonNull(pictureId)) {
            PicturePo picturePo = pictureDataService.getPictureById(pictureId)
                    .orElseThrow(() -> new BusinessException(ErrorCodeEnum.PictureNotExist));
            spaceId = picturePo.getSpaceId();
            if (Objects.nonNull(spaceId)) {
                // 看什么类型的空间
                SpacePo spacePo = spaceDataService.getSpaceById(spaceId)
                        .orElseThrow(() -> new BusinessException(ErrorCodeEnum.SpaceNotExist));
                return getPermissionsBySpaceType(ALL_PERMISSIONS, userId, spaceId, spacePo);
            } else {
                // 公共空间，本人和管理员有所有权限
                if (picturePo.getCreateBy().equals(userId) || roleDataService.isAdmin(userId)) {
                    return ALL_PERMISSIONS;
                } else {
                    // 不是自己的图片，仅可查看
                    return Collections.singletonList("picture:view");
                }
            }
        }
        // 如果 pictureId 也没有，表示查询公共图库，管理员有所有权限，其他人仅查看权限
        return getPublicSpacePermissions(userId, ALL_PERMISSIONS);
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return Collections.emptyList();
    }

    /**
     * 从请求中获取上下文对象
     */
    private SpaceUserAuthContext getAuthContextByRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String contentType = request.getHeader(Header.CONTENT_TYPE.getValue());
        SpaceUserAuthContext authRequest;

        // 获取请求参数
        if (ContentType.JSON.getValue().equals(contentType)) {
            String body = JakartaServletUtil.getBody(request);
            authRequest = JSONUtil.toBean(body, SpaceUserAuthContext.class);
        } else {
            Map<String, String> paramMap = JakartaServletUtil.getParamMap(request);
            authRequest = BeanUtil.toBean(paramMap, SpaceUserAuthContext.class);
        }

        // 根据请求路径区分请求参数中id的含义
        Long id = authRequest.getId();
        if (Objects.nonNull(id)) {
            String requestURI = request.getRequestURI();
            if (requestURI.startsWith(contextPath)) {
                // 去掉URL前缀
                requestURI = requestURI.substring(contextPath.length());
            }
            if (requestURI.startsWith("/picture")) {
                authRequest.setPictureId(id);
            } else if (requestURI.startsWith("/space/user")) {
                // 顺序不可换，避免匹配失败
                authRequest.setSpaceUserId(id);
            } else if (requestURI.startsWith("/space")) {
                authRequest.setSpaceId(id);
            }
        }
        return authRequest;
    }

    /**
     * 根据空间类型分配权限
     */
    private List<String> getPermissionsBySpaceType(List<String> ALL_PERMISSIONS, Long userId, Long spaceId, SpacePo spacePo) {
        switch (spacePo.getType()) {
            case PRIVATE -> {
                // 私人空间，仅本人和管理员有权限
                if (spacePo.getCreateBy().equals(userId) || roleDataService.isAdmin(userId)) {
                    return ALL_PERMISSIONS;
                } else {
                    return Collections.emptyList();
                }
            }
            case TEAM -> {
                // 团队空间，需要查询 SpaceUser 获取角色的权限
                SpaceUserPo spaceUserPo = spaceUserDataService.getSpaceUserByUserIdAndSpaceId(userId, spaceId)
                        .orElse(null);
                if (Objects.nonNull(spaceUserPo)) {
                    return spaceUserAuthManager.listPermissionsByRole(spaceUserPo.getRoleCode());
                } else {
                    return Collections.emptyList();
                }
            }
            default -> {
                // 未知空间类型，返回空权限
                return Collections.emptyList();
            }
        }
    }

    /**
     * 获取公共空间权限
     */
    private List<String> getPublicSpacePermissions(Long userId, List<String> ALL_PERMISSIONS) {
        if (roleDataService.isAdmin(userId)) {
            return ALL_PERMISSIONS;
        }
        // 普通用户仅有查看权限
        return Collections.singletonList("picture:view");
    }

    /**
     * 判断对象的所有字段是否为空
     *
     * @param obj 对象
     * @author Ma Chengrui
     * @since 2025/9/28
     */
    private boolean isAllFieldsNull(Object obj) {
        if (Objects.isNull(obj)) {
            return true;
        }
        return BeanUtil.beanToMap(obj).values().stream().allMatch(Objects::isNull);
    }

    /**
     * 利用反射机制判断对象的所有字段是否为空
     * 避免obj中字段有默认值
     *
     * @param obj 对象
     * @author Ma Chengrui
     * @since 2025/9/28
     */
    private boolean isAllFieldsNullByReflect(Object obj) {
        if (Objects.isNull(obj)) {
            return true;
        }
        return Arrays.stream(ReflectUtil.getFields(obj.getClass()))
                .map(field -> ReflectUtil.getFieldValue(obj, field))
                .allMatch(Objects::isNull);
    }


}
